#include  "thread.h"
#include  "pcb.h"
#include  "doxon.h"
#include  "queue.h"
#include  "schedule.h"
#include  "semaphor.h"
#include  "kernsem.h"

#include  <_null.h>


const StackSize defaultStackSize = 4096;
const Time defaultTimeSlice = 100;
Priority defaultPriority = 50;

#define DEFAULT_MTS 60

Time minTimeSlice() {
    return DEFAULT_MTS;
}

void dispatch() {
    Doxon::dispatch();
}

Thread::Thread (UID uid,
        Priority priority,
        StackSize stackSize,
        Time timeSlice) {
    lock();
    myPCB = new PCB(this, uid, priority, stackSize, timeSlice);
    unlock();
}
Thread::~Thread() {
    lock();
    waitToComplete();
    delete myPCB;
    unlock();
}

void Thread::start() {
    lock();
    myPCB->state = PCB::READY;
    myPCB->init_stack();
    Scheduler::put(myPCB);
    unlock();
}

void Thread::waitToComplete() {
    lock();

    /* Ne mozemo da cekamo nad niti koja je zavrsena */
    if ( myPCB->state == PCB::FINISHED || myPCB->state == PCB::NEW )
        goto unl;

    /* Nit ne moze da ceka samu sebe */
    if (myPCB == (PCB*)Doxon::running)
        goto unl;

    /* 
     * Niti ne mogu da cekaju glavnu nit da zavrsi sa radom jer kada se
     * to desi, sve niti u sistemu se gase kaskadno...
     */
    if (this == Doxon::starting)
        goto unl;

    if (this == Doxon::idle) 
        goto unl;

    Doxon::running->state = PCB::BLOCKED;
    myPCB->waitQueue->put((PCB*)Doxon::running); 
    Doxon::dispatch();
unl:unlock();

}

void Thread::Interrupt() {
    lock();
    if ( myPCB->state == PCB::BLOCKED ) {
        myPCB->time_wait   = (Time)0;
        myPCB->time_passed = (Time)0;

        /* Cuva konzistentnu vrednost semafora */
        if ( myPCB->kern_sem_own != NULL ) {
            myPCB->kern_sem_own->del( myPCB );
            myPCB->kern_sem_own = NULL;
        }
        myPCB->wait_return = 2;

        myPCB->state = PCB::READY;
        Scheduler::put(myPCB);
        Doxon::dispatch();
    }
    unlock();
}

ID Thread::getId() {
    return myPCB->id;
}

UID Thread::getUID() {
    return myPCB->uid;
}

Thread* Thread::getThreadById(ID id) {
    return PCB::getThreadById(id);
}

ID Thread::getIdOf(UID uid) {
    return (ID)uid;
}

